package com.hhs.storage.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hhs.storage.bean.*;
import com.hhs.storage.service.*;
import com.hhs.storage.util.NumberUtil;
import com.hhs.storage.util.StringUtil;
import com.hhs.storage.util.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/flowable")
@Slf4j
public class FlowableController {
    //流程定义的操作接口
    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private IdentityService identityService;

    @Qualifier("processEngine")
    @Autowired
    private ProcessEngine processEngine;

    @Resource
    private ZrSimulateService zrSimulateService;

    @Resource
    private HttpServletRequest request;
    @Resource
    private ProjectPlanService projectPlanService;
    @Resource
    private ProjectWorkFlowService projectWorkFlowService;
    @Resource
    private BaseDepartmentService baseDepartmentService;
    @Resource
    private ProjectMemberService projectMemberService;
    @Resource
    private BaseUserService userService;
    @Resource
    private ProjectFavorateService projectFavorateService;
    @Resource
    private BaseRoleService baseRoleService;
    @Resource
    private ZrSimulateFlowResultService zrSimulateFlowResultService;
    @RequestMapping(value = "createDefinition")
    /**
     * 部署流程定义，相当于把类生成在类加载区，整个工程只可以做一次
     */
    public ResponseBean createDefinition(String resourceName,String flowName) throws FileNotFoundException {
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("processes/ask_for_myleave.bpmn20.xml")
                .name(flowName)
                .deploy();
        return ResponseBean.success(deploy);
    }

    /**
     * 删除流程定义
     */
    @RequestMapping(value = "deleteDefinition")
    public ResponseBean deleteDefinition(String deployId) {
        repositoryService.deleteDeployment(deployId, true);
        log.info(repositoryService.createProcessDefinitionQuery().orderByProcessDefinitionId().asc().list().toString());
        return ResponseBean.success(null);
    }

    /**
     * 启动流程实例
     */
    @RequestMapping(value = "add")
    public ResponseBean add(String userId,String money,String descption) {
        // 获取启动流程的服务
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 构建流程变量
        HashMap<String, Object> map = new HashMap<>();
        map.put("taskUser", userId);
        map.put("money", money);
        map.put("descption", descption);
        //Expense是我们绘制流程图时自己所填写的key
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Expense", map);
        return ResponseBean.success("提交成功.流程Id为：" + processInstance.getId());
    }


    /**
     * 获取审批管理列表
     * taskDefKey 对应流程的id
     */
    @RequestMapping(value = "/list")
    public Object list(String taskDefKey,String userId) {
        TaskQuery taskQuery = taskService.createTaskQuery();
        if (!StringUtils.isEmpty(userId)){
            taskQuery = taskQuery.taskAssignee(userId);
            System.out.println(userId);
        }
        if (!StringUtils.isEmpty(taskDefKey)){
            taskQuery = taskQuery.taskDefinitionKey(taskDefKey);
        }
        List<Task> tasks = taskQuery.orderByTaskCreateTime().desc().list();
        List list = new ArrayList();
        for (Task task : tasks) {
            Map map = new HashMap();
            map.put("id",task.getId());
            map.put("name",task.getName());
            map.put("variables",taskService.getVariables(task.getId()));
            map.put("processId",task.getProcessInstanceId());
            map.put("assignee",task.getAssignee());
            list.add(map);
        }

        return ResponseBean.success(list);


    }



    /**
     * 批准
     *
     * @param taskId 任务ID
     */
    @RequestMapping(value = "apply")
    public String apply(String taskId) {
        System.out.println("------------------"+taskId);
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new RuntimeException("流程不存在");
        }
        //通过审核
        HashMap<String, Object> map = new HashMap<>();
        map.put("outcome", "通过");
        taskService.complete(taskId, map);
        return "processed ok!";
    }

    /**
     * 拒绝
     */

    @RequestMapping(value = "reject")
    public String reject(String taskId) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("outcome", "驳回");
        taskService.complete(taskId, map);
        return "reject";
    }


    /**
     * 生成流程图
     *
     * @param processId 任务ID
     * @return
     */
    @RequestMapping(value = "processDiagram")
    public String genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();

        //流程走完的不显示图
        if (pi == null) {
            return processId;
        }
        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();

        //得到正在执行的Activity的Id
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows,
                engconf.getActivityFontName(), engconf.getLabelFontName(),
                engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            byte[] bytes = outputStream.toByteArray();
            return Base64.encodeBase64String(bytes);
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * 认领任务
     * 任务id,认领人名
     */
    @RequestMapping(value = "claimTask")
    public ResponseBean claimTask(String taskId,String claimPerson) {
        // 构建流程变量
        taskService.claim(taskId, claimPerson);
        List<Task> list = taskService.createTaskQuery().taskUnassigned().list();
        return ResponseBean.success(list);
    }


    //----------------------



    /**
     * 查找流程定义
     */
    @RequestMapping(value = "findDefinition")
    public ResponseBean findDefinition() {
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
        log.info(list.toString());
        System.out.println(list.toString());
        return ResponseBean.success(null);
    }


    /**
     * 得到流程实例
     */
    @RequestMapping(value = "getInstanse")
    public ResponseBean getInstanse(String definitionId) {
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processDefinitionId(definitionId).list();
        log.info(list.toString());
        System.out.println(list.toString());
        return ResponseBean.success(null);
    }


    /**
     * 完成任务
     */
    @RequestMapping(value = "completeTask")
    public ResponseBean complentTask(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new RuntimeException("流程不存在");
        }
        // 构建流程变量
        Map map=new HashMap();
        map.put("approve",2);
        taskService.complete(taskId, map);
        return ResponseBean.success("processed ok!");
    }




    /**
     * 得到任务
     */
    @RequestMapping(value = "getTask")
    public ResponseBean getTask(String instanceId) {
        List<Task> list = taskService.createTaskQuery().processInstanceId(instanceId).list();
        System.out.println(list);
        return ResponseBean.success(null);
    }

    /**
     * 得到任务2
     * 参数为候选组名
     */
    @RequestMapping(value = "getTask2")
    public ResponseBean getTask2(String candidateGroup) {
        List<Task> list = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).list();
        return ResponseBean.success(list);
    }

    /**
     * 查看已经完成了的任务
     */
    @RequestMapping(value = "lookCompleted")
    public ResponseBean lookCompleted(String definitionId) {
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processDefinitionId(definitionId)
                // 查询已经完成的
                .finished()
                // 指定排序字段和排序
                .orderByHistoricActivityInstanceEndTime()
                .asc()
                .list();
        return ResponseBean.success(list);
    }

    /**
     * 通过processDefinition.id和resType导出流程XML或图片资源
     * @param response
     * @throws Exception
     */
    @GetMapping(value = "/res/exp")
    public void resourceRead( String definitionId,HttpServletResponse response) throws Exception {
        /** resType取值 “image/png”或“text/xml” **/
        InputStream resourceAsStream = resourceRead(definitionId, "image/png");
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }
    /**
     * 读取流数据
     * @param definitionId
     * @param resType
     * @return
     * @throws Exception
     */
    public InputStream resourceRead(String definitionId, String resType) throws Exception {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(definitionId).singleResult();
        String resourceName = "";
        if (resType.equals("image/png")) {
            resourceName = processDefinition.getDiagramResourceName();
        } else if (resType.equals("text/xml")) {
            resourceName = processDefinition.getResourceName();
        }
        InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
        return resourceAsStream;
    }

    /**
     * 绘制强调当前节点的流程图
     */
    @GetMapping(value = "/process/diagram")
    public void genProcessDiagram(@RequestParam("processInstanceId") String processInstanceId, HttpServletResponse httpServletResponse) throws Exception {
        InputStream resourceAsStream = genProcessDiagramDb(processInstanceId);
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            httpServletResponse.getOutputStream().write(b, 0, len);
        }
    }

    /**
     * 绘制流程待办
     * @param processId
     * @return
     * @throws Exception
     */
    public InputStream genProcessDiagramDb(String processId) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        //流程走完的不显示图
        if (pi == null) {
            return null;
        }
        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();
        //得到正在执行的Activity的Id
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 2.0, true);
        return in;
    }

    /**
     * 我的待办
     * @return
     */
    @RequestMapping(value = "/mywaitwork")
    public Map<String,Object> mywaitwork(InputParam inputParam){
        QueryWrapper<ZrSimulate> qw=new QueryWrapper<>();
        qw.eq("user_id", SysUtil.getLoginUserId(request));
        if(inputParam.getType()==0){
            qw.eq("status",0);
        }else if(inputParam.getType()==1){
            qw.eq("status",1).or().eq("status",2);
        }else if(inputParam.getType()==2){
            qw.notInSql("id","select id from zr_simulate where status=0");
        }
        //搜索名字
        if(!StringUtil.iszNull(inputParam.getName())){
            qw.inSql("project_id","select id from project_plan where name like '%"+inputParam.getName()+"%'");
        }
        //搜索状态
        if(inputParam.getStatus()!=null){
            qw.inSql("project_id","select id from project_plan where state="+inputParam.getStatus());
        }
        //搜索部门
        if(!StringUtil.iszNull(inputParam.getDepartId())){
            qw.inSql("project_id","select id from project_plan where depart_id='"+inputParam.getDepartId()+"'");
        }
        //搜索时间
        if((!StringUtil.iszNull(inputParam.getStartDate()))&&(!StringUtil.iszNull(inputParam.getEndDate()))){
            qw.inSql("project_id","select id from project_plan where start_time between '"+inputParam.getStartDate()+"' and '"+inputParam.getEndDate()+"'");
        }
        //搜索完成未完成重点关注
        if(!StringUtil.iszNull(inputParam.getSelectList())){
            List<String> selectList= Arrays.asList(inputParam.getSelectList().split(","));
            if(!(selectList.contains("0")&&selectList.contains("1"))){
                if(selectList.contains("0")){
                    qw.inSql("project_id","select id from project_plan where state=0");
                }
                if(selectList.contains("1")){
                    qw.inSql("project_id","select id from project_plan where state=1 ");
                }
            }
            if(selectList.contains("2")){
                qw.inSql("project_id","select project_id from project_favorate where favorate=1");
            }
        }
        //项目归类筛选
        if(!StringUtil.iszNull(inputParam.getTtypes())){
            qw.inSql("project_id","select id from project_plan where ttype in ("+StringUtil.toCommaStringSql(Arrays.asList(inputParam.getTtypes().split(",")))+")");
        }
        //项目分类筛选
        if(!StringUtil.iszNull(inputParam.getXmfls())){
            qw.inSql("project_id","select id from project_plan where project_type in ("+StringUtil.toCommaStringSql(Arrays.asList(inputParam.getXmfls().split(",")))+")");
        }
        //会签类型筛选
        if(!StringUtil.iszNull(inputParam.getHqStatuses())){
            List<String> hqStatuesList=Arrays.asList(inputParam.getHqStatuses().split(","));
            Collections.sort(hqStatuesList);
            int doc=0;
            if(hqStatuesList.contains("0")){
                qw.inSql("flow_id","select distinct(flow_id) from zr_simulate where status=0");
                doc++;
            }
            if(hqStatuesList.contains("1")){
                if(doc==0){
                    qw.inSql("flow_id","SELECT flow_id FROM zr_simulate AA WHERE user_id='"+SysUtil.getLoginUserId(request)+"' GROUP BY flow_id HAVING CEIL(COUNT(*)*0.66)<=(SELECT COUNT(*) FROM zr_simulate BB WHERE AA.`flow_id`=BB.`flow_id` and BB.status=1)");
                }else{
                    qw.or().inSql("flow_id","SELECT flow_id FROM zr_simulate AA WHERE user_id='"+SysUtil.getLoginUserId(request)+"' GROUP BY flow_id HAVING CEIL(COUNT(*)*0.66)<=(SELECT COUNT(*) FROM zr_simulate BB WHERE AA.`flow_id`=BB.`flow_id` and BB.status=1)");
                }
            }
            if(hqStatuesList.contains("2")){
                if(doc==0){
                    qw.inSql("flow_id","SELECT flow_id FROM zr_simulate AA WHERE user_id='"+SysUtil.getLoginUserId(request)+"' GROUP BY flow_id HAVING CEIL(COUNT(*)*0.66)<=(SELECT COUNT(*) FROM zr_simulate BB WHERE AA.`flow_id`=BB.`flow_id` and BB.status=2)");
                }else{
                    qw.or().inSql("flow_id","SELECT flow_id FROM zr_simulate AA WHERE user_id='"+SysUtil.getLoginUserId(request)+"' GROUP BY flow_id HAVING CEIL(COUNT(*)*0.66)<=(SELECT COUNT(*) FROM zr_simulate BB WHERE AA.`flow_id`=BB.`flow_id` and BB.status=2)");
                }
            }
        }
        //负责人筛选
        int doc=0;
        if(!StringUtil.iszNull(inputParam.getFzrIds())){
            qw.inSql("project_id","select project_id from project_member where identity_type=0 and user_id in ("+StringUtil.toCommaStringSql(inputParam.getFzrIds().split(","))+")");
            doc++;
        }
        //协助人筛选
        if(!StringUtil.iszNull(inputParam.getXzrIds())){
            if(doc==0){
                qw.inSql("project_id","select project_id from project_member where identity_type=3 and user_id in ("+StringUtil.toCommaStringSql(inputParam.getXzrIds().split(","))+")");
            }else{
                qw.or().inSql("project_id","select project_id from project_member where identity_type=3 and user_id in ("+StringUtil.toCommaStringSql(inputParam.getXzrIds().split(","))+")");
            }
        }
        //如果是审批角色,就要列出审批项目
        List<BaseRole> roles = baseRoleService.getByUserId(SysUtil.getLoginUserId(request));
        List<String> userRoleIds = roles.stream().map(BaseRole::getId).collect(Collectors.toList());
        if(isSpRole(userRoleIds)){
            qw.or().isNull("user_id").and(item->item.eq("is_current",1));
        }
        Page<ZrSimulate> page = zrSimulateService.page(new Page<ZrSimulate>(inputParam.getPage(), inputParam.getSize()), qw);
        for (ZrSimulate z:page.getRecords()){
            ProjectPlan byId = projectPlanService.getById(z.getProjectId());
            byId.setDepartName(baseDepartmentService.getById(byId.getDepartId()).getName());
            //查询成员
            QueryWrapper<ProjectMember> qw2 = new QueryWrapper<>();
            qw2.eq("project_id", z.getProjectId());
            qw2.orderByAsc("identity_type");
            List<ProjectMember> projectMemberList = projectMemberService.list(qw2);
            for (int i = 0; i < projectMemberList.size(); i++) {
                ProjectMember member = projectMemberList.get(i);
                BaseUser user = userService.getById(member.getUserId());
                member.setName(user.getName());
                member.setUser(user);
            }
            byId.setProjectMemberList(projectMemberList);
            //设置收藏
            QueryWrapper<ProjectFavorate> qwf=new QueryWrapper<>();
            qwf.eq("project_id", z.getProjectId());
            int count = projectFavorateService.count(qwf);
            byId.setFavorate(count);

            z.setProjectPlan(byId);
            ProjectWorkFlow byIdf = projectWorkFlowService.getById(z.getFlowId());
            byIdf.setUserName(userService.getById(byIdf.getUserId()).getName());
            z.setProjectWorkFlow(byIdf);
            //如果是审批项目加入审批人
            if(StringUtil.iszNull(z.getFlowId())){
                QueryWrapper<ZrSimulateFlowResult> qwzr=new QueryWrapper<>();
                qwzr.eq("simulate_id", z.getId());
                List<ZrSimulateFlowResult> listsp = zrSimulateFlowResultService.list(qwzr);
                for (ZrSimulateFlowResult zs:listsp){
                    Map<String, Object> allById = userService.getAllById(zs.getUserId());
                    ProjectPlan proj = projectPlanService.getById(zs.getProjectId());
                    zs.setProject(proj);
                    zs.setUser((BaseUser) allById.get("user"));
                }
                z.getSpUsers().addAll(listsp);
            }else{
                //如果不是审批项目加入会签人
                QueryWrapper qw3 = new QueryWrapper();
                qw3.eq("flow_id", z.getFlowId());
                List<ZrSimulate> list = zrSimulateService.list(qw3);
                for (ZrSimulate zrSimulate : list) {
                    zrSimulate.setName(userService.getById(zrSimulate.getUserId()).getName());
                    List<String> l=new ArrayList<>();
                    List<BaseDepartment> bb = baseDepartmentService.findByUserId(zrSimulate.getUserId());
                    for (BaseDepartment baseDepartment : bb) {
                        l.add(baseDepartment.getName());
                    }
                    zrSimulate.setDepartNames(l.toString());
                }
                byIdf.setHqUsers(list);
            }
        }
        Map res=new HashMap();
        List<ZrSimulate> allList=new ArrayList<>();
        //待办类型
        if(!StringUtil.iszNull(inputParam.getDdTypes())){
            List<String> ddtypesList=Arrays.asList(inputParam.getDdTypes().split(","));
            if(ddtypesList.contains("0")){
                allList.addAll(page.getRecords());
            }
        }else {
            allList.addAll(page.getRecords());
        }
        res.put("code",1);
        res.put("rows",allList);
        res.put("total",page.getTotal());
        return res;
    }

    /**
     * 判断是不是审批角色
     * @param userRoleIds
     * @return
     */
    private static boolean isSpRole(List<String> userRoleIds) {
        return userRoleIds.contains(ProjectPlanService.FIRSET_NODE_FLAG) || userRoleIds.contains(ProjectPlanService.SECOND_NODE_FLAG) || userRoleIds.contains(ProjectPlanService.THIRD_NODE_FLAG);
    }

    /**
     * 会签方法
     * @return
     */
    @RequestMapping(value = "/hqpassOrNo")
    public Map<String,Object> hqpassOrNo(ZrSimulate zrSimulate){
        zrSimulate.setOpTime(LocalDateTime.now());
        zrSimulateService.saveOrUpdate(zrSimulate);
        return ResponseInfo.success();
    }
}
